#ifndef DSPSIMULATOR_SIMULATOR_H
#define DSPSIMULATOR_SIMULATOR_H

#include <queue>
#include <simulator/targetMachine/targetMachine.h>
#include <simulator/instFetcher.h>
#include <simulator/instruction/instruction.h>
#include <simulator/instruction/delayInstruction.h>
#include <simulator/llvmJit/llvmJit.h>
#include <simulator/targetMachine/timer.h>

class Simulator {
protected:
    std::shared_ptr<TargetMachine> m_targetMachine;         // 目标机
    std::shared_ptr<InstFetcher> m_instFetcher;             // 取指器
    std::vector<std::shared_ptr<Instruction>> m_instProto;  // 目标机支持的指令原型
    std::shared_ptr<LLVMJit> m_llvmJit;                     // llvm jit执行引擎
    std::priority_queue<DelayInst, std::vector<DelayInst>, std::greater<>> m_delayQueue;      // 延迟指令队列，最小堆
    std::vector<std::shared_ptr<Timer>> m_timers;           // 定时器
    std::set<u64> m_breakPoints;       // 断点地址
public:
    /**
     * 模拟器的构造函数
     * @param targetMachine 目标机
     * @param instFetcher 取指器
     * @param llvmJit  llvm jit执行引擎
     */
    Simulator(std::shared_ptr<TargetMachine> targetMachine, std::shared_ptr<InstFetcher> instFetcher,
              std::shared_ptr<LLVMJit> llvmJit)
            : m_targetMachine(targetMachine), m_instFetcher(instFetcher), m_llvmJit(llvmJit) {
        m_timers.emplace_back(std::make_shared<Timer>());
    }

    virtual ~Simulator() = default;

    /**
     * 获取模拟器支持的目标机
     * @return 目标机
     */
    std::shared_ptr<TargetMachine> getDspMachine();

    /**
     * 运行模拟器的接口函数
    */
    virtual void run() = 0;

    /**
     * 添加目标机器支持的指令原型
     */
    virtual void addAllInstructionProto() = 0;

    /**
     * 添加新的定时器
     * @param timer 新的定时器
     */
    void addTimer(std::shared_ptr<Timer> timer);

    /**
     * 加载指令对应的ir函数到llvm jit执行引擎中，并构建ir函数执行需要的全局信息
     */
    void loadInstIRIntoJit();

protected:

    /**
    * 取指函数
    * @return 当前周期取指器取出的指令数据集合
    */
    virtual std::vector<std::shared_ptr<InstInfo>> fetch() = 0;

    /**
     * 根据指令数据集合解码出一系列对应的指令对象
     * @param instInfo 指令数据集合
     * @return 解码出的一系列指令
     */
    virtual std::vector<std::shared_ptr<Instruction>> decode(std::vector<std::shared_ptr<InstInfo>> instInfos) = 0;

    /**
     * 执行指令
     * @param instruction 一系列指令
     */
    virtual void execute(std::vector<std::shared_ptr<Instruction>> instructions) = 0;

    /**
     * 该函数用于添加全局变量，以供ir函数执行
     */
    virtual void addGlobalVariable(llvm::LLVMContext *llvmContext, llvm::Module *llvmModule) = 0;

    /**
     * 该函数用于添加全局变量的映射，用于将全局变量映射到正确的地址上
     */
    virtual void addGlobalMapping(std::shared_ptr<llvm::ExecutionEngine> executionEngine) = 0;

    /**
     * cpu进入到下一个时钟周期
     */
    void nextCycle();

    /**
     * 将有delaySlot的指令添加到延时队列中
     * @param instruction
     */
    void addInstIntoDelayQueue(std::shared_ptr<Instruction> instruction);

    /**
     * 执行延时队列中可以执行的延时指令
     */
    void executeDelayInst();
};

#endif //DSPSIMULATOR_SIMULATOR_H
